﻿using System;
using System.CodeDom.Compiler;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text.RegularExpressions;

namespace BrandonHaynes.Data
	{
	class Program
		{
		static void Main(string[] args)
			{
			Console.WriteLine("IDataReader Adapter Generator (brandonhaynes.org)");
			Console.WriteLine("Copyright (C) 2008 Brandon Haynes; all rights reserved.");
			Console.WriteLine();

			IEnumerable<IEntity> entities;
			var arguments = new YACLAP.ArgParser(args);

			if ((!arguments.Exists("assembly") && !arguments.Exists("entities")) 
				|| !arguments.Exists("output"))
				{
				DisplayUsage();
				return;
				}

			// Targeting types in an assembly
			if (arguments.Exists("assembly"))
				{
				var assembly = Assembly.LoadFrom(arguments["assembly"].Value);
				var typeRegEx = arguments.Exists("entities") ? arguments["entities"].Value : ".*";
				var types = assembly.GetTypes().Where(type => Regex.IsMatch(type.Name, typeRegEx));
				entities = types.Select(type => new TypeAdapter(type)).Cast<IEntity>(); 
				Console.WriteLine("Using assembly: " + assembly.GetName().Name);
				}
			// Targeting entities in an Linq to Entities EDMX 
			else
				{
				Console.WriteLine("Using entity schema: " + arguments["entities"].Value);
				entities = EdmAdapter.LoadEntities(arguments["entities"].Value);
				}

			// Generate typed DataReader AST
			var unit = DataReaderCodeGenerator.GenerateDataReaders(entities);

			// Display the readers generated
			foreach (var entity in entities)
				Console.WriteLine("Generating IDataReader for: " + entity.Name);
			if (!entities.Any())
				Console.WriteLine("Warning: No entities found to generate.");


			// Compile the AST into target language
			var compiler = !arguments.Exists("language") || arguments["language"].Value.Equals("C#", StringComparison.OrdinalIgnoreCase) ? (CodeDomProvider)
				new Microsoft.CSharp.CSharpCodeProvider() :
				new Microsoft.VisualBasic.VBCodeProvider();

			using(var output = new StreamWriter(arguments["output"].Value))
				compiler.GenerateCodeFromCompileUnit(unit, output, null);

			Console.WriteLine("Done.");
			}

		private static void DisplayUsage()
			{
			Console.WriteLine("Usage: IDataReaderAdapterGenerator /assembly:[source assembly filename] /output:[output class filename] [/entities:[entity regex] [/language:vb|c#]");
			Console.WriteLine("       IDataReaderAdapterGenerator /entities:[.NET Entity Framework EDMX file] /output:[output class filename] [/entities:[entity regex] [/language:vb|c#]");
			Console.WriteLine("");
			Console.WriteLine("One of:");
			Console.WriteLine("Assembly: Filename of source assembly from which to load target entities");
			Console.WriteLine("Entities: Filename of source .NET Entities Framework EDMX file");
			Console.WriteLine("");
			Console.WriteLine("Output: Output file for generated class(es)");
			Console.WriteLine(@"Types: A regular expression of entities used to generate classes (default "".*"" (Examples: ""BrandonHaynes.*"")");
			Console.WriteLine(@"Language: The language used for generated classes.  Must be one of { C#, VB}");
			Console.WriteLine("");
			Console.WriteLine("Example: IDataReaderAdapterGenerator /assembly:BrandonHaynes.IDataReaderAdapterGenerator.dll /output:BrandonHaynes.DataReaders.cs /entities:SampleEntity /language:c#");
			Console.WriteLine("Example: IDataReaderAdapterGenerator /entities:Entities.EDMX /output:BrandonHaynes.DataReaders.cs /entities:SampleEntity /language:c#");
			}
		}
	}
